package combine.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class LongPrimarykeyGenerator {
	private short nodeId;
	private int initId;
	private long nextId;
	private boolean inited = false;

	@SuppressWarnings("unused")
	private LongPrimarykeyGenerator() {
	}

	public LongPrimarykeyGenerator(short nodeId) throws BaseException {
		if(nodeId < 0) {
			throw new BaseException("nodeId[" + nodeId + "] cannot be negative(<0)");
		}
		this.nodeId = nodeId;
	}

	public LongPrimarykeyGenerator(short nodeId, int initId) throws BaseException {
		if(nodeId < 0) {
			throw new BaseException("nodeId[" + nodeId + "] cannot be negative(<0)");
		}
		this.nodeId = nodeId;
		this.initId = initId;
	}

	public synchronized void initialize(Connection connection, String tableName, String primaryKeyFieldName) throws BaseException {
		if(this.inited) {
			throw new BaseException("this instance has initialized");
		}
		long nodeIdOnHigh = ((long)this.nodeId << 48);
		long primaryKeyLowerLimit = nodeIdOnHigh | initId;
		long primaryKeyUpperLimit = nodeIdOnHigh | 0xffffffffffffl;
		
		String sql = "SELECT max(" + primaryKeyFieldName
				+ ") AS maxPrimaryKey  FROM " + tableName + " WHERE ("
				+ primaryKeyFieldName + ">=" + primaryKeyLowerLimit + ") AND ("
				+ primaryKeyFieldName + " <= " + primaryKeyUpperLimit + ")";
		Statement statement = null;
		ResultSet rs = null;

		try {
			statement = connection.createStatement();
			rs = statement.executeQuery(sql);
			long maxPrimaryKey = 0;
			while (rs.next()) {
				maxPrimaryKey = rs.getLong("maxPrimaryKey");
			}
			if (maxPrimaryKey != 0) {
				this.nextId = maxPrimaryKey + 1;
			} else {
				this.nextId = primaryKeyLowerLimit;
			}
			this.inited = true;
		} catch (Exception e) {
			throw new BaseException("table[" + tableName + "] primaryKey[" + primaryKeyFieldName + "] initialize fail");
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}

				if (statement != null) {
					statement.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
	}

	public short getNodeId() throws BaseException {
		return nodeId;
	}

	public int getInitId() {
		return initId;
	}

	public synchronized long getNextId() throws BaseException {
		if(this.inited) {
			return this.nextId ++;
		} else {
			throw new BaseException("Error: LongIdGenerator not initialized");
		}
	}
}
